import { PureComponent } from 'react'
import { Table, Tabs, Button, Switch, Row, Form, Select, Input } from 'antd'
import { connect } from 'react-redux'
import {
  getProductList,
  getProductType,
  getProductCategory,
  changeProductShow,
} from '@/reducer/product'

// 声明文件放在外部的好处
// 1, 可复用
// 2, 减少当前文件中的代码复杂程度
import {
  IProductState,
  IProductType,
  IGoodsType,
  ICategory,
} from '@/types/product'

import Header from '@/commponents/common/Layout/Header'
import ExportExcel from '@/utils/exportExcel'

import './style.less'

interface IProps {
  getProductList: Function // 获取商品列表
  getProductType: Function // 获取商品状态分类
  getProductCategory: Function // 获取商品类型分类
  [key: string]: any
}

interface IState {
  page?: number // 页码
  limit?: number // 每页数量 默认10
  cate_id?: number // 分类id 默认0
  type?: string // product type 是否出售中等状态 默认1
  store_name?: string // 搜索关键字，可以为空
  sales?: string // 排序方式 默认normal
}

/**
 * 商品列表页
 * 因为当前页面被嵌套在layout容器中，为了避免每次layout中状态变化都重新渲染当前页面，这里使用了PureComponent
 */
class ProductList extends PureComponent<IProps, IState> {
  // 要在当前类中使用基类中未定义的属性，需要先声明
  // 如果当前类中使用了constructor，也可以在constructor中直接定义
  public oldState: string = JSON.stringify(this.state)
  // state是在Component中声明过的，可以直接定义
  // 组件自身的状态，由IState进行约束，我们必须要让自己的state长得与IState完全一致
  state = {
    page: 1,
    limit: 10,
    cate_id: 0,
    store_name: '',
    type: '1',
    sales: 'normal',
  }

  columns = [
    { title: '商品ID', dataIndex: 'id' }, // A
    {
      title: '商品图',
      dataIndex: 'image',
      render: (image: any) => (
        <img className="product-image" src={image} alt="" />
      ),
    }, // B
    { title: '商品名称', dataIndex: 'store_name' }, // C
    { title: '商品售价', dataIndex: 'price' },
    { title: '销量', dataIndex: 'sales' },
    { title: '库存', dataIndex: 'stock' },
    { title: '排序', dataIndex: 'sort' },
    {
      title: '状态',
      dataIndex: 'is_show',
      render: (_: any, item: any) => (
        <Switch
          checkedChildren="下架"
          unCheckedChildren="上架"
          defaultChecked
          onChange={() => {
            this.props.changeProductShow({
              id: item.id,
              status: item.is_show === 0 ? 1 : 0,
            })
          }}
        />
      ),
    },
    {
      title: '操作',
      dataIndex: 'operation',
      render: (_: any, item: any) => (
        <>
          <Button type="text">编辑</Button>|
          <Button type="text">查看评论</Button>|
          <Button type="text">移到回收站</Button>
        </>
      ),
    },
  ]

  /**
   * 获取商品列表的方法
   * 这个方法会在每一次state发生变化时都进行请求，为了减少代码复杂度，在这里将它封装成一个方法，使其可以被复用
   */
  getProductList = () => {
    this.props.getProductList({
      // 当前页只管理了商品列表的相关状态，可以使用直接解构的方式
      ...this.state,
    })
  }

  /**
   * 在页面首次渲染成功后，获取依赖的数据
   */
  componentDidMount() {
    // 商品的状态分类列表
    this.props.getProductType()
    // 商品类型分类列表
    this.props.getProductCategory()
    // 商品列表
    this.getProductList()
  }

  /**
   * 页面状态发生变化，props发生变化都会导致这个生命周期函数被执行
   * 因为我们每次请求都会改变redux中的状态，进而影响到当前组件的props
   * 所以在这里每一次请求都会导致被执行
   */
  componentDidUpdate() {
    // 当页码、搜索关键词、cateId、type发生变化时，请求接口获取数据
    // 获取数据列表
    // 为了避免每一次props变化都会造成重新请求，我们需要加多一个条件判断
    if (this.handlerOldState(this.state)) {
      this.getProductList()
    }
  }

  handlerOldState = (state: IState) => {
    const stateStr = JSON.stringify(state)
    // 这里使用了一个oldState属性，往上滚动到当前类的顶部看看是怎么定义的
    if (this.oldState !== stateStr) {
      this.oldState = stateStr
      return true
    }
    return false
  }

  /**
   * 需要展示不同状态的商品
   * @param type
   */
  changeProductType = (type: string) => {
    // 改变状态
    // 在生命周期中setState是一个异步处理函数
    // 我们在这里改变的内容是需要等待的，所以，立即请求实际上拿的还是原来的参数
    this.setState({
      type,
    })
  }

  /**
   * 商品分类id发生变化
   * @param cate_id
   */
  cateChange = (cate_id: number) => {
    this.setState({
      cate_id,
    })
  }

  /**
   * 关键字搜索
   * @param store_name
   */
  onSearch = (store_name: string) => {
    this.setState({
      store_name,
    })
  }

  /**
   * 导出excel功能
   */
  exportExcel = () => {
    // 当前列表中显示的数据
    const list = this.props.productList.list
    // 将列表中需要展示的数据传给导出插件
    ExportExcel(this.columns, list, '商品管理.xlsx')
  }

  render() {
    // props的类型由IProps进行约束
    const { productList, productType, productCategory } = this.props

    return (
      <div className="center product product-list">
        <Header title="商品管理">
          <Tabs
            defaultActiveKey={this.state.type}
            // 商品状态的变化（售中，下架等状态）
            onChange={activeKey => this.changeProductType(activeKey)}
          >
            {/* productType */}
            {productType.map((item: IProductType) => (
              <Tabs.TabPane
                key={item.type}
                tab={`${item.name}(${item.count})`}
              ></Tabs.TabPane>
            ))}
          </Tabs>
        </Header>
        <div className="container">
          <Row>
            <Form name="pl-filter" layout="inline">
              <Form.Item label="商品分类" name="cateId">
                <Select style={{ width: 120 }} onChange={this.cateChange}>
                  {productCategory.map((item: ICategory) => (
                    <Select.Option key={item.id} value={item.id}>
                      {item.html.replaceAll(
                        /\|-{5}/g,
                        (a: string, b: string, c: string) => {
                          return c === a
                            ? ''
                            : parseInt(b) === 0
                            ? '# '
                            : '--> '
                        }
                      ) + item.cate_name}
                    </Select.Option>
                  ))}
                </Select>
              </Form.Item>
              <Form.Item label="商品搜索" name="username">
                <Input.Search
                  placeholder="input search text"
                  onSearch={this.onSearch}
                  enterButton
                />
              </Form.Item>
            </Form>
            <Row>
              <Button
                type="primary"
                icon={<>+ </>}
                onClick={() => this.props.history.push('/product/add_product')}
              >
                添加商品
              </Button>
              <Button type="primary" onClick={() => this.exportExcel()}>
                导出
              </Button>
            </Row>
          </Row>

          {productList && (
            <Row className="table-wrap">
              <Table
                className="components-table"
                columns={this.columns}
                pagination={{
                  total: productList.count,
                  current: this.state.page,
                  pageSize: this.state.limit,
                }}
                dataSource={productList.list}
                // 不知道为什么，不加这个会报key的错误。。早先的时候是没有这个问题的
                rowKey={item => `product_${item.id}`}
              />
            </Row>
          )}
        </div>
      </div>
    )
  }
}

export default connect(
  // 注意，这里是类型声明
  (state: { productInfo: IProductState }) => state.productInfo,
  {
    getProductList,
    getProductType,
    getProductCategory,
    changeProductShow,
  }
)(ProductList)
